#include "Renderer.h"
#include <cstdlib>

namespace Graphics
{
	Renderer::Renderer(Window* window)
	{
		this->_width = window->getWidth();
		this->_height = window->getHeight();
		this->_window = window;
	}

	void Renderer::Clear(Pixel& pixel)
	{
		int currentBuffer = this->_window->getCurrentBufferPointer();
		Pixel* data = this->_window->getBuffers()[currentBuffer].getDataPtr();

		data = new Pixel[_width * _height];

		for(int i = 0; i < _width * _height; i++)
			data[i] = pixel;
	}

	void Renderer::Draw(ImageBuffer* image, int x, int y)
	{
		// check clipping with screen buffer borders
		int right = x + image->getWidth();
		int bottom = y + image->getHeight();

		if( right > 0 && x < _width &&
			bottom > 0 && y < _height)
		{
			Pixel* data = image->getDataPtr();
			// render using validated clipping rectangle
			for(int xLoc = x; xLoc < right; xLoc++)
				for(int yLoc = y; yLoc < bottom; yLoc++)
					DrawPoint( data[xLoc * image->getWidth() + yLoc], xLoc, yLoc);
		}
	}

	void Renderer::Draw(Sprite* sprite)
	{
		ImageBuffer* buffer = (sprite->getData());
		Draw(buffer, sprite->Position.X, sprite->Position.Y);
	}

	void Renderer::DrawPoint(Pixel& pixel, int x, int y)
	{
		if(x >= 0 && x < _width && y >= 0 && y < _height)
		{
			int currentBuffer = this->_window->getCurrentBufferPointer();
			this->_window->getBuffers()[currentBuffer].setData(x, y, pixel);
		}
	}

	// implementation of Bresenham line drawing algorithm
	void Renderer::DrawLine(Pixel& pixel, int x1, int y1, int x2, int y2)
	{
		// if x1 == x2 or y1 == y2, then it does not matter what we set here
		int delta_x(x2 - x1);
		signed char ix((delta_x > 0) - (delta_x < 0));
		delta_x = std::abs(delta_x) << 1;
 
		int delta_y(y2 - y1);
		signed char iy((delta_y > 0) - (delta_y < 0));
		delta_y = std::abs(delta_y) << 1;
 
		DrawPoint(pixel, x1, y1);
 
		if (delta_x >= delta_y)
		{
		    // error may go below zero
		    int error(delta_y - (delta_x >> 1));
 
		    while (x1 != x2)
		    {
		        if (error >= 0)
		        {
		            if (error || (ix > 0))
		            {
		                y1 += iy;
		                error -= delta_x;
		            }
		            // else do nothing
		        }
		        // else do nothing
 
		        x1 += ix;
		        error += delta_y;
 
				DrawPoint(pixel, x1, y1);
		    }
		}
		else
		{
		    // error may go below zero
		    int error(delta_x - (delta_y >> 1));
 
		    while (y1 != y2)
		    {
		        if (error >= 0)
		        {
		            if (error || (iy > 0))
		            {
		                x1 += ix;
		                error -= delta_y;
		            }
		            // else do nothing
		        }
		        // else do nothing
 
		        y1 += iy;
		        error += delta_x;
 
				DrawPoint(pixel, x1, y1);
		    }
		}
	}

}